#pragma once

#include <libdxfrw/drw_interface.h>
#include <libdxfrw/libdwgr.h>
#include <libdxfrw/libdxfrw.h>
#include <qlib/layout/library.h>
#include <memory>
#include <unordered_set>

namespace qlib {

/**
 * @brief dxf file reader and writer
 *
 * 使用方法参考libdxfrw
 */
class QLIB_API DxfRWInterface : public DRW_Interface {
 private:
  /* data */
 public:
  DxfRWInterface(/* args */);
  ~DxfRWInterface();

  /**
   * @brief
   *
   * @param filename
   * @param cells
   * @param layer_name
   * 图层编号对应的图层名字，dxf每个图层使用名字关联，而不使用编号
   */
  void write_dxf(const std::string& filename, std::vector<std::shared_ptr<qlib::Cell>> cells,
                 const std::unordered_map<uint32_t, std::string>& layer_name = {},
                 std::map<uint32_t, std::vector<std::vector<std::pair<qlib::Vec2d, double>>>> post_sim_polygons =
                     std::map<uint32_t, std::vector<std::vector<std::pair<qlib::Vec2d, double>>>>());

  /**
   * @brief
   *
   * @param fname
   * @param top_cell_name
   * 顶层cell的名字，dxf中不属于任何block的几何图形被写入到顶层cell
   * @return std::set<std::shared_ptr<Cell>>
   */
  std::vector<std::shared_ptr<qlib::Cell>> read_dxf(const std::string& fname, const std::string& top_cell_name, const double& scale_factor = 1.0);

  std::unordered_map<std::string, uint32_t> getNameLayer();  // 用作导入dxf图层信息的适配

  // reader part, stores all in class dx_data
  // header
  virtual void addHeader(const DRW_Header* data) override;

  // tables
  virtual void addLType(const DRW_LType& data) override;
  virtual void addLayer(const DRW_Layer& data) override;
  virtual void addDimStyle(const DRW_Dimstyle& data) override;
  virtual void addVport(const DRW_Vport& data) override;
  virtual void addTextStyle(const DRW_Textstyle& data) override;
  virtual void addAppId(const DRW_AppId& data) override;

  // blocks
  virtual void addBlock(const DRW_Block& data) override;
  virtual void endBlock() override;

  virtual void setBlock(const int /*handle*/) override;  // unused

  // entities
  virtual void addPoint(const DRW_Point& data) override;
  virtual void addLine(const DRW_Line& data) override;
  virtual void addRay(const DRW_Ray& data) override;
  virtual void addXline(const DRW_Xline& data) override;
  virtual void addArc(const DRW_Arc& data) override;
  virtual void addCircle(const DRW_Circle& data) override;
  virtual void addEllipse(const DRW_Ellipse& data) override;
  virtual void addLWPolyline(const DRW_LWPolyline& data) override;
  virtual void addPolyline(const DRW_Polyline& data) override;
  virtual void addSpline(const DRW_Spline* data) override;
  virtual void addKnot(const DRW_Entity& data) override;

  virtual void addInsert(const DRW_Insert& data) override;
  virtual void addTrace(const DRW_Trace& data) override;
  virtual void add3dFace(const DRW_3Dface& data) override;
  virtual void addSolid(const DRW_Solid& data) override;
  virtual void addMText(const DRW_MText& data) override;
  virtual void addText(const DRW_Text& data) override;
  virtual void addDimAlign(const DRW_DimAligned* data) override;
  virtual void addDimLinear(const DRW_DimLinear* data) override;
  virtual void addDimRadial(const DRW_DimRadial* data) override;
  virtual void addDimDiametric(const DRW_DimDiametric* data) override;
  virtual void addDimAngular(const DRW_DimAngular* data) override;
  virtual void addDimAngular3P(const DRW_DimAngular3p* data) override;
  virtual void addDimOrdinate(const DRW_DimOrdinate* data) override;
  virtual void addLeader(const DRW_Leader* data) override;
  virtual void addHatch(const DRW_Hatch* data) override;
  virtual void addViewport(const DRW_Viewport& data) override;
  virtual void addImage(const DRW_Image* data) override;

  virtual void linkImage(const DRW_ImageDef* data) override;

  // writer part, send all in class dx_data to writer
  virtual void addComment(const char* /*comment*/) override;

  virtual void writeHeader(DRW_Header& data) override;

  virtual void writeBlocks() override;
  //+ only send the name, needed by the reader to prepare handles of blocks &
  // blockRecords
  virtual void writeBlockRecords() override;
  // write entities of model space and first paper_space
  virtual void writeEntities() override;
  virtual void writeLTypes() override;
  virtual void writeLayers() override;
  virtual void writeTextstyles() override;
  virtual void writeVports() override;
  virtual void writeDimstyles() override;
  virtual void writeAppId() override;

 private:
  // 重置writer和reader以备反复使用
  void resetWriter(const std::string& fname);
  void resetReader(const std::string& filename, const std::string& fname);
  std::shared_ptr<dxfRW> m_dxf_read_writer;  // pointer to writer, needed to send data
  std::set<std::shared_ptr<qlib::Cell>> m_cells;
  std::map<std::shared_ptr<qlib::Cell>, std::vector<std::shared_ptr<qlib::Reference>>> cellToCells;
  std::shared_ptr<qlib::Cell> m_curr_cell;        // 当前正在处理的gdscell，cell与dxf文件中的block对应
  std::shared_ptr<qlib::Cell> m_top_cell;         // 导入dxf时，没有装在block中的图形放置在top_cell中
  std::shared_ptr<qlib::Cell> m_export_top_cell;  // 导出dxf时，放在顶层的cell
  std::unordered_map<uint32_t, std::string> m_layer_name;
  std::unordered_map<std::string, uint32_t> m_name_layer;
  uint64_t m_layer{256};        // 当前正在处理的gds图形的图层编号 2024-7-29 取值：256,是指定的一个稍大的图层编号，为了适应图层编号适配中的问题
  double m_scale_factor = 1.0;  // 比例因子
  std::map<uint32_t, std::vector<std::vector<std::pair<qlib::Vec2d, double>>>> m_post_sim_polygons;  // 后仿处理后的多边形数据
};
}  // namespace qlib

#ifdef __EMSCRIPTEN__
void bind_dxfrw();
#endif